// 异步工作器（异步消息处理器）
#ifndef __M_LOOP_H__
#define __M_LOOP_H__
#include "buffer.hpp"
#include <thread>
#include <mutex>
#include <memory>
#include <atomic>
#include <condition_variable>
#include <functional>

namespace Mylog
{
    enum class LooperType
    {
        // 1. 安全模式，数据达到缓冲区上线进行阻塞, 避免资源耗尽风险
        // 2. 不安全模式，缓冲区空间没有限制，未满时扩容 —— 测试
        AsyncSafe,
        AsyncUnSafe
    };

    using functor = std::function<void(Buffer &)>;
    class AsyncLooper
    {
    public:
        using ptr = std::shared_ptr<AsyncLooper>;
        AsyncLooper(const functor &cb, LooperType looper_type = LooperType::AsyncSafe)
            : _stop(false), _looper_type(looper_type)
            , _thread(&AsyncLooper::threadEntry, this)
            , _callback(cb) {}
        ~AsyncLooper(){ stop(); }
        void push(const char *data, size_t len)
        {
            if (_stop) return;
            std::unique_lock<std::mutex> lock(_mutex);
            if (_looper_type == LooperType::AsyncSafe)
                _cond_pro.wait(lock, [&]() { return _pro_buffer.writeAbleSize() >= len; });
            _pro_buffer.push(data, len);
            // 唤醒消费线程，消费线程在处理完数据之后需要和生产缓冲区进行交换，但如果生产缓冲区为空，此时消费线程会进行阻塞
            _cond_con.notify_all(); 
        }
        void stop()
        {
            _stop = true;
            _cond_con.notify_all(); // 唤醒所有的工作线程
            _thread.join();
        }

    private:
        // 线程入口函数 —— 工作线程，处理数据。处理完后初始化缓冲区，并交换缓冲区
        void threadEntry()
        {
            while (1)
            {
                // 1. 交换缓冲区数据
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    if (_stop && _pro_buffer.empty()) break;
                    _cond_con.wait(lock, [&](){ return _stop || !_pro_buffer.empty(); });
                    _con_buffer.swap(_pro_buffer);
                    // 2. 唤醒生产线程
                    if (_looper_type == LooperType::AsyncSafe)
                        _cond_pro.notify_all();
                }
                // 3. 被唤醒后，对消费缓冲区数据进行处理
                _callback(_con_buffer);
                // 4.初始化消费缓冲区
                _con_buffer.reset();
            }
        }

    private:
        functor _callback; // 具体消费缓冲区数据处理函数，由异步工作器使用者传入
    private:
        LooperType _looper_type;
        std::atomic<bool> _stop; // 工作器停止标志
        Buffer _pro_buffer;      // 生产缓冲区
        Buffer _con_buffer;      // 消费缓冲区
        std::mutex _mutex;
        std::condition_variable _cond_pro;
        std::condition_variable _cond_con;
        std::thread _thread; // 异步工作器对应的工作线程
    };
}
#endif